package com.gyt.manager.service.impl;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.gyt.manager.common.base.exception.BaseException;
import com.gyt.manager.common.base.response.Page;
import com.gyt.manager.common.base.response.Response;
import com.gyt.manager.common.component.CosComponent;
import com.gyt.manager.common.component.EnvComponent;
import com.gyt.manager.common.constant.Base;
import com.gyt.manager.common.enums.LabelLockEnum;
import com.gyt.manager.common.enums.LabelStateEnum;
import com.gyt.manager.common.dto.EmailDTO;
import com.gyt.manager.common.utils.DateTimeUtility;
import com.gyt.manager.common.utils.EmailUtil;
import com.gyt.manager.common.utils.FreeMarkerUtil;
import com.gyt.manager.dao.risk.DalMetaLabelInfoMapper;
import com.gyt.manager.dao.risk.LabelAlarmLogMapper;
import com.gyt.manager.dao.risk.LabelInfoMapper;
import com.gyt.manager.domain.req.LabelExcelReq;
import com.gyt.manager.domain.req.LabelLevelReq;
import com.gyt.manager.domain.req.LabelReq;
import com.gyt.manager.domain.risk.DalMetaLabelInfo;
import com.gyt.manager.domain.risk.LabelAlarmLog;
import com.gyt.manager.domain.risk.LabelInfo;
import com.gyt.manager.service.LabelService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author v_yantgao
 */
@Service
public class LabelServiceImpl implements LabelService {


    private static final Logger LOGGER = LoggerFactory.getLogger(LabelServiceImpl.class);
    private static final String DO_LABEL_ID =
            "cast(flabel_id AS signed INTEGER)";
    private static final String FLABEL_ID = "flabel_id";
    public static final List<String> LABEL_LEVEL =
            Arrays.asList("L1", "L2", "L3", "L4");
    private static final String WHITE_KEY = "label.level.alarm.person";
    private static String URL = "https://www.baidu.com/?labelId=";
    @Autowired
    private LabelInfoMapper labelInfoMapper;
    @Autowired
    private DalMetaLabelInfoMapper dalMetaLabelInfoMapper;
    @Autowired
    private LabelAlarmLogMapper labelAlarmLogMapper;
    @Autowired
    private CosComponent cosComponent;
    private static final Map<String, String> labelMap = Maps.newHashMap();

    private List<String> columns = Arrays.asList("labelId","labelName","labelLevel","colName",
            "tbName","labelType","labelTag","labelUplineTime","labelState","isLabelUse");
    static {
        labelMap.put("labelId","标签ID");
        labelMap.put("labelName","标签名称");
        labelMap.put("labelLevel","标签等级");
        labelMap.put("colName","字段名");
        labelMap.put("tbName","标签主题表");
        labelMap.put("labelType","标签类型");
        labelMap.put("labelTag","标签所属类目");
        labelMap.put("labelUplineTime","上线日期");
        labelMap.put("labelState","标签状态");
        labelMap.put("isLabelUse","是否锁定");
    }

    @Override
    public byte[] exportLabelToExcel(
            LabelExcelReq req, HttpServletResponse response) {
        Assert.notNull(req, "请选择导出的字段");
        HSSFWorkbook workbook = new HSSFWorkbook();
        HSSFSheet sheet = workbook.createSheet("画像数据");
        HSSFRow headerRow = sheet.createRow(0);
        List<String> filedColumns = req.getFiledColumns();
        List<Map<String, Object>> mapList = labelInfoMapper.selectAll();
        List<String> header = Lists.newArrayList();
        for (int i = 0; i < filedColumns.size(); i++) {
            header.add(labelMap.get(filedColumns.get(i)));
        }
        for (int i = 0; i < header.size(); i++) {
            headerRow.createCell(i).setCellValue(header.get(i));
        }
        int current =1;
        for (Map<String, Object> map : mapList) {
            HSSFRow row = sheet.createRow(current++);
            for (int i = 0; i < filedColumns.size(); i++) {
                Object obj = map.get(filedColumns.get(i));
                row.createCell(i).setCellValue(null2Empty(obj));
            }
        }
        String fileName = UUID.randomUUID().toString().replaceAll("-", "") + ".xls";
        try {
            fileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.name());
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
        response.setHeader(
                "Content-Disposition",
                "attachment; filename=\"" + fileName + "\"; filename*=utf-8''" + fileName);
        try {
            OutputStream outputStream = response.getOutputStream();
            workbook.write(outputStream);
            outputStream.close();
            return workbook.getBytes();
        } catch (IOException e) {
            e.printStackTrace();
        }
        LOGGER.info("fff");
        return null;
    }

    @Override
    public void sendEmail(String fdate){
        Map<String, Object> map = Maps.newHashMap();
        map.put("fdate", fdate);
        map.put("fsendStatus", NumberUtils.BYTE_ZERO);
        List<LabelAlarmLog> sendAlarms = labelAlarmLogMapper.selectByCondition(map);
        if (CollectionUtils.isNotEmpty(sendAlarms)) {
            Map<String, List<LabelAlarmLog>> listMap = sendAlarms.stream().
                    collect(Collectors.groupingBy(LabelAlarmLog::getFowners));
            for (Map.Entry<String, List<LabelAlarmLog>> entry : listMap.entrySet()) {
                String user = entry.getKey();
                //todo 白名单邮件发送人过滤
                List<LabelAlarmLog> sendLogs = entry.getValue();
                Date createTime = sendLogs.get(0).getFcreateTime();
                String currentTime = DateTimeUtility.timeofnow(
                        createTime, DateTimeUtility.PATTERN_DATE_TIME);
                List<Long> ids = Lists.newArrayList();
                for (LabelAlarmLog log : sendLogs) {
                    log.setUrl(URL + log.getFlabelId());
                    ids.add(log.getFid());
                }
                //封装邮件信息
                Map<String, Object> emailMap = Maps.newHashMap();
                emailMap.put("currentTime", currentTime);
                emailMap.put("alarmDatas", sendLogs);
                if (StringUtils.isNotBlank(user) && "jerome".equals(user)) {
                    emailMap.put("owners", user);
                    String content = FreeMarkerUtil.templateToString("levelAlarm.ftl", emailMap);
                    EmailDTO emailDTO = new EmailDTO();
                    emailDTO.setTitle("等级异常邮件");
                    emailDTO.setContentType("text/html;charset=utf-8");
                    emailDTO.setContent(content);
                    emailDTO.setTo("782819023@qq.com");
                    emailDTO.setFrom("961920261@qq.com");
                    Boolean aBoolean = EmailUtil.sendEmail(emailDTO);
                    if (!EnvComponent.isDev()) {
                        if (aBoolean) {
                            labelAlarmLogMapper.batchUpdateByIds(ids);
                        }
                    }
                }
            }
        }
    }

    @Override
    public void batchAddLabelAlarmInfo(String fdate) {
        //获取 已上线 且等级检测有变化的集合
        List<LabelAlarmLog> list = labelAlarmLogMapper.getAllLevelUpdateInfo();
        if (CollectionUtils.isNotEmpty(list)) {
            Date date = new Date();
            String dateToday = fdate;
            //dateToday = DateTimeUtility.dateToday(date);
            List<LabelAlarmLog> records = Lists.newArrayList();
            for (LabelAlarmLog alarmLog : list) {
                String fowners = alarmLog.getFowners();
                Set<String> users = Base.parseStrToSets(fowners);
                for (String user : users) {
                    LabelAlarmLog log = new LabelAlarmLog();
                    log.setFcreateTime(date);
                    log.setFcurLevel(alarmLog.getFcurLevel());
                    log.setFdate(dateToday);
                    log.setFdetectLevel(alarmLog.getFdetectLevel());
                    log.setFlabelId(alarmLog.getFlabelId());
                    log.setFlabelName(alarmLog.getFlabelName());
                    log.setFmodifyTime(date);
                    log.setFsendStatus(NumberUtils.BYTE_ZERO);
                    log.setFowners(user);
                    records.add(log);
                }
            }
            if (CollectionUtils.isNotEmpty(records)) {
                int count = labelAlarmLogMapper.batchInsert(records);
                LOGGER.info("batchInsert succeed, count:{}", count);
            }
        }
    }

    @Override
    public Page<LabelInfo> findLabelInfos(String userName, LabelReq labelReq) {
        String sortType = labelReq.getSortType();
        Boolean flag = Base.checkSort(sortType);
        if (!flag) {
            throw new BaseException(Response.CODE_ERROR, "sortType传参错误");
        }
        if (1 == labelReq.getLabelType()) {
            labelReq.setFowner(userName);
        }
        if (FLABEL_ID.equals(labelReq.getOrderKey())) {
            labelReq.setOrderKey(DO_LABEL_ID);
        }
        Map<String, Object> paramMap = Maps.newHashMap();
        paramMap.put("keyword", labelReq.getKeyword());
        paramMap.put("fowner", labelReq.getFowner());
        paramMap.put("flabelState", labelReq.getFlabelState());
        paramMap.put("flabelLevel", labelReq.getFlabelLevel());
        paramMap.put("orderKey", labelReq.getOrderKey());
        paramMap.put("sortType", sortType);
        Page.startPage(labelReq.getPageNum(), labelReq.getPageSize());
        List<LabelInfo> labelInfos = labelInfoMapper.findLabelInfos(paramMap);
        Page<LabelInfo> from = Page.from(labelInfos);
        return from;
    }

    @Override
    public Boolean batchUpdateLabelLevel(LabelLevelReq labelLevelReq) {
        List<Long> keyIds = labelLevelReq.getFid();
        if (CollectionUtils.isNotEmpty(keyIds)) {
            String flabelLevel = labelLevelReq.getFlabelLevel();
            if (!LABEL_LEVEL.contains(labelLevelReq.getFlabelLevel())) {
                throw new BaseException(Response.CODE_ERROR, "flabelLevel传参错误");
            }
            Map<String, Object> paramMap = new HashMap<>();
            paramMap.put("flabelLevel", flabelLevel);
            paramMap.put("keyIds", keyIds);
            return labelInfoMapper.batchUpdateLabelLevel(paramMap);
        }
        return false;
    }

    @Override
    public Boolean whetherLockedLabel(Long fid, String isLock) {
        LabelLockEnum lockEnum = LabelLockEnum.check(isLock);
        if (lockEnum == null) {
            throw new BaseException(Response.CODE_ERROR, "isLock传参错误");
        }
        LabelInfo labelInfo = labelInfoMapper.selectByPrimaryKey(fid);
        if (labelInfo != null) {
            Byte labelUse = labelInfo.getFisLabelUse();
            if (lockEnum.getValue().byteValue() != labelUse) {
                LabelInfo updateLabel = new LabelInfo();
                updateLabel.setFid(fid);
                updateLabel.setFisLabelUse(lockEnum.getValue().byteValue());
                int record = labelInfoMapper.updateByFid(updateLabel);
                return record > 0;
            }
        }
        return false;
    }

    @Override
    public List<Map<String, Object>> findLabelStatus() {
        List<Map<String, Object>> list = Lists.newArrayList();
        for (LabelStateEnum stateEnum : LabelStateEnum.values()) {
            Map<String, Object> map = Maps.newHashMap();
            map.put("value", stateEnum.getValue());
            map.put("desc", stateEnum.getDesc());
            list.add(map);
        }
        return list;
    }

    @Override
    public void batchAddLabelInfo(String fdate) {
        Map<String, Object> para = Maps.newHashMap();
        para.put("fdate", fdate);
        List<DalMetaLabelInfo> list = dalMetaLabelInfoMapper.selectByCondition(para);
        //获取所有锁定的标签集合
        para.remove("fdate");
        para.put("fisLabelUse", NumberUtils.INTEGER_ONE);
        List<LabelInfo> lockedInfos = labelInfoMapper.findLabelInfos(para);
        Date date = new Date();
        if (CollectionUtils.isNotEmpty(list)) {
            List<LabelInfo> records = Lists.newArrayList();
            for (DalMetaLabelInfo metaLabelInfo : list) {
                LabelInfo info = getLabelInfo(date, metaLabelInfo);
                records.add(info);
            }
            if (CollectionUtils.isNotEmpty(records)) {
                Boolean flag = batchSave(records);
                if (flag) {
                    int count = labelInfoMapper.updateRuleNum();
                    LOGGER.info("updateRuleNum record:{}", count);
                }
                if (CollectionUtils.isNotEmpty(lockedInfos)) {
                    for (LabelInfo info : lockedInfos) {
                        String labelLevel = info.getFlabelLevel();
                        String labelId = info.getFlabelId();
                        labelInfoMapper.updateByLabelId(labelLevel, labelId);
                    }
                    LOGGER.info("<--batch updateByLabelId succeed-->");
                }
            }
        }
    }

    private LabelInfo getLabelInfo(Date date, DalMetaLabelInfo metaLabelInfo) {
        LabelInfo info = new LabelInfo();
        info.setFcreateTime(date);
        info.setFmodifyTime(date);
        info.setFruleNum(0);
        info.setFisLabelUse(NumberUtils.BYTE_ZERO);
        info.setFstoreServer(metaLabelInfo.getFstoreServer());
        info.setFdate(metaLabelInfo.getFdate());
        info.setFlabelId(metaLabelInfo.getFlabelId());
        info.setFetlTime(metaLabelInfo.getFetlTime());
        info.setFlabelName(metaLabelInfo.getFlabelName());
        info.setFlabelLevel(metaLabelInfo.getFlabelLevel());
        info.setFserverId(metaLabelInfo.getFserverId());
        info.setFdbName(metaLabelInfo.getFdbName());
        info.setFtbName(metaLabelInfo.getFtbName());
        info.setFcolName(metaLabelInfo.getFcolName());
        info.setFlabelType(metaLabelInfo.getFlabelType());
        info.setFlabelTag1(metaLabelInfo.getFlabelTag1());
        info.setFlabelTag2(metaLabelInfo.getFlabelTag2());
        info.setFlabelTag3(metaLabelInfo.getFlabelTag3());
        Long uplineTime = metaLabelInfo.getFlabelUplineTime();
        Date labelOnlineTime = DateTimeUtility.parseYmdHmsContinue(
                uplineTime == null ? null : String.valueOf(uplineTime));
        info.setFlabelUplineTime(labelOnlineTime);
        String labelState = metaLabelInfo.getFlabelState();
        LabelStateEnum stateEnum = LabelStateEnum.check(labelState);
        info.setFlabelState((byte) stateEnum.getValue());
        info.setFowner(metaLabelInfo.getFowner());
        return info;
    }

    /**
     * 批量保存.
     *
     * @param list
     * @return boolean
     */
    public Boolean batchSave(List<LabelInfo> list) {
        int size = list.size();
        final int unitNum = 2500;
        int startIndex = 0;
        int endIndex;
        while (size > 0) {
            if (size > unitNum) {
                endIndex = startIndex + unitNum;
            } else {
                endIndex = startIndex + size;
            }
            List<LabelInfo> insertData = list.subList(startIndex, endIndex);
            labelInfoMapper.batchAdd(insertData);
            size = size - unitNum;
            startIndex = endIndex;
        }
        return true;
    }
    private String null2Empty(Object obj){
        String str = "";
        if(obj != null){
            str = obj.toString();
        }
        return str;
    }

}
